/*
 * This file is part of the GUI_SDK.
 *
 * Copyright (c) 2019-2019 Link-Card.Co.Ltd. All rights reserved.
 *
 * Authors:
 *    JiangYong <1556631285@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * 'Software'), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Function:   handle events
 * Created on: 2019-10-05
 */

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <ftw.h>

#include "bsp.h"
#include "event.h"
#include "key.h"
#include "menu.h"
#include "wifi.h"
#include "lcd.h"
#include "parameter.h"
#include "tw9900.h"

#include "log2file.h"

int wifi_signal_level_switch(int signal_level)
{
	int ret;
	if (signal_level <= -88) {
		ret = 0;
	} else if (signal_level <= -77) {
		ret = 1;
	} else if (signal_level <= -55) {
		ret = 2;
	} else {
		ret = 3;
	}
	return ret;
}

static int nvram_load_param(const char *name, char *value)
{
	FILE *fp;
	char buf[128] = {0}, cmd[128] = {0};

	sprintf(cmd, "nvram get wireless %s", name);
	if ((fp = popen(cmd, "r")) == NULL) {
		perror("popen");
		printf("popen error: %s/n", strerror(errno)); 
		return -1;
	}
	fgets(buf, sizeof(buf), fp);
	strtok(buf, "\n");
	strcpy(value, buf);
	// printf("%s = %s\n", name, buf);

	pclose(fp);
	return 0;
}

static void nvram_save_param(const char *name, char *value)
{
	char cmd[128] = {0};

	sprintf(cmd, "nvram set wireless %s '%s'", name, value);
	system(cmd);
}

static void nvram_commit(void)
{
	system("nvram commit");
}

static int string_is_zh(const char *str)
{
	while (*str) {
		if (*str > 127) {
			return -1;
		}
		str++;
	}
	return 0;
}

static int setup_normal_search_wifi(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	if (!pobj->devctx.wifi.val) {
		return 0;
	}

	struct sNode *p, *s, wifi_node, wifi2_node;
	struct bss_info bss[32];
	memset(bss, 0, sizeof(bss));
	int ret = 0;

	nvram_load_param("STASSID", wifi_node.essid);
	nvram_load_param("STASSID2", wifi2_node.essid);
	clearList(&pobj->devctx.list_head);
	initList(&p);

	for (int i = 0; i < 5; i++) {
		ret = JN_Wifi_STA_Search(bss);
		if (ret > 0) {
			break;
		}
		usleep(500 * 1000);
	}
	if (ret > 0) {
		struct sNode tmp;
		for (int i = 0; i < ret && i < 32; i++) {
			if (!string_is_zh(bss[i].ssid) && bss[i].ssid[0]) {
				tmp.signal_level = bss[i].signal_mbm/100;
				strcpy(tmp.essid, bss[i].ssid);
				insertFirstList(&p, &tmp);
			}
		}

		pobj->devctx.wifi_connect_status.val = 0;
		pobj->devctx.wifi_index.val = 0;
		pobj->devctx.wifi_index.max = 0;
		pobj->devctx.wifi_page_index.val = 0;
		pobj->devctx.wifi_page_index.max = 0;

		for(pobj->devctx.list_head = p; pobj->devctx.list_head != NULL; pobj->devctx.list_head = pobj->devctx.list_head->next){
			while(deleteValueList(&(pobj->devctx.list_head->next), pobj->devctx.list_head->essid)){
				;
			}
		}
		for(s = p; s != NULL; s = s->next){
			insertOrderList(&pobj->devctx.list_head, s);
		}
		clearList(&p);

		if (findList(pobj->devctx.list_head, &wifi_node) && findList(pobj->devctx.list_head, &wifi2_node)) {
			deleteValueList(&pobj->devctx.list_head, wifi2_node.essid);
			insetPosList(&pobj->devctx.list_head, 2, &wifi2_node);
			deleteValueList(&pobj->devctx.list_head, wifi_node.essid);
			insertFirstList(&pobj->devctx.list_head, &wifi_node);
		} else if (findList(pobj->devctx.list_head, &wifi_node)) {
			deleteValueList(&pobj->devctx.list_head, wifi_node.essid);
			insertFirstList(&pobj->devctx.list_head, &wifi_node);
		} else if (findList(pobj->devctx.list_head, &wifi2_node)) {
			deleteValueList(&pobj->devctx.list_head, wifi2_node.essid);
			insertFirstList(&pobj->devctx.list_head, &wifi2_node);
		}

		pobj->devctx.wifi_index.max = sizeList(pobj->devctx.list_head);
		pobj->devctx.wifi_page_index.max = (pobj->devctx.wifi_index.max % 6) ? (pobj->devctx.wifi_index.max / 6 + 1) : (pobj->devctx.wifi_index.max / 6);
		pobj->devctx.wifi_signal_level.val = wifi_signal_level_switch(pobj->devctx.list_head->signal_level);
		pobj->curid = id_search_wifi;
		// printf("wifi_index.max = %d, wifi_page_index.max = %d\n", pobj->devctx.wifi_index.max, pobj->devctx.wifi_page_index.max);
	}
	return 0;
}

/*
 * 在选择WiFi热点的界面，长按“enter”键
 * 		1.当前的焦点 WiFi 信号，之前成功连接过的，如果现在WiFi是连接状态，直接退出，不在连接状态，直接连接
 * 		1.如果不是之前连接的，进入输入WiFi密码界面
 * 在其他界面，长按“enter”键，进入选择WiFi热点的界面
 */
static int setup_normal_adjust_lcd_brightness(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	pobj->devctx.lcd_brightness.val++;
	if (pobj->devctx.lcd_brightness.val > pobj->devctx.lcd_brightness.max) {
		pobj->devctx.lcd_brightness.val = 0;
	}
	sony_driver_brightness_level(pobj->devctx.lcd_brightness.val);

	hal_save_para(PARA_BRIGHTNESS, pobj->devctx.lcd_brightness.val);
	save_paramemters();

	return 0;
}

static int setup_normal_switch_wifi(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	pobj->devctx.wifi.val = 1 - pobj->devctx.wifi.val;
	if (pobj->devctx.wifi.val) {
		system("/mnt/default/wifi.sh on");
	} else {
		system("/mnt/default/wifi.sh off");
	}

	return 0;
}

static int setup_search_wifi_connect(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	if (0 == pobj->devctx.wifi_connect_status.val) {
		int pos = pobj->devctx.wifi_index.val + pobj->devctx.wifi_page_index.val * 6;
		char nvram_ssid[128] = {0}, nvram_ssid2[128] = {0}, nvram_password[128] = {0}, nvram_password2[128] = {0};
		struct sNode wifi_node;

		getElem(pobj->devctx.list_head, pos + 1, &wifi_node);
		nvram_load_param("STASSID", nvram_ssid);
		nvram_load_param("STASSID2", nvram_ssid2);
		nvram_load_param("STAPasswd", nvram_password);
		nvram_load_param("STAPasswd2", nvram_password2);

		/* 读取保存的两个ssid，比较目前选中的WiFi热点是否为保存的WiFi之一 */
		if (!strcmp(nvram_ssid, wifi_node.essid) || !strcmp(nvram_ssid2, wifi_node.essid)) {
			JN_Wifi_STA_Getstatus(&pobj->devctx.wifi_status.val);	// 判断WiFi是否为连接状态

			/* 如果已经连接并且选中的是保存的WiFi */
			if (pobj->devctx.wifi_status.val && !strcmp(nvram_ssid, wifi_node.essid)) {
				pobj->curid = id_normal;
				return 0;
			} else { // 未连接或者当前选中的是另一个保存的WiFi热点
				if (!strcmp(nvram_ssid, wifi_node.essid)) { // 未连接并且选中的为保存的WiFi
					JN_Wifi_STA_Setup(nvram_ssid, nvram_password);
					/* 获取状态判断连接是否成功 */
					JN_Wifi_STA_Getstatus(&pobj->devctx.wifi_status.val);
				} else if (!strcmp(nvram_ssid2, wifi_node.essid)) { // 未连接或者选中的为保存的WiFi2
					JN_Wifi_STA_Setup(nvram_ssid2, nvram_password2);
					/* 获取状态判断连接是否成功 */
					JN_Wifi_STA_Getstatus(&pobj->devctx.wifi_status.val);
					if (pobj->devctx.wifi_status.val) {
						nvram_save_param("STASSID", nvram_ssid2);
						nvram_save_param("STAPasswd", nvram_password2);
						nvram_save_param("STASSID2", nvram_ssid);
						nvram_save_param("STAPasswd2", nvram_password);
						nvram_commit();
					}
				}
				if (pobj->devctx.wifi_status.val) {
					pobj->curid = id_normal;
				} else {
					setup_normal_search_wifi(pobj);
				}
			}
		} else {	// 如果选中的WiFi不是保存的两个WiFi之一，直接退出
			pobj->curid = id_normal;
		}
	}

	return 0;
}

static int setup_search_wifi_choice(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;
	
	switch (pobj->devctx.wifi_connect_status.val)
	{
	case 0:
		pobj->devctx.wifi_connect_status.val = 1;	// 进入选择连接WiFi或者忘记
		pobj->devctx.status_sel.val = 0;
		break;
	case 1:
		if (0 == pobj->devctx.status_sel.val) {
			pobj->curid = id_password;
			pobj->devctx.wifi_password_sel.val = 0;
			pobj->devctx.wifi_password_sel.max = 9;
			pobj->devctx.password_enter_num.val = 0;
		} else {
			if (pobj->devctx.wifi_status.val && !pobj->devctx.wifi_index.val && !pobj->devctx.wifi_page_index.val) {
				disconnect_wifi();
				pobj->devctx.wifi_status.val = 0;
			}
			pobj->devctx.wifi_connect_status.val = 0;
		}
		break;
	}

	return 0;
}

static int setup_search_wifi_switch_pre(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	switch (pobj->devctx.wifi_connect_status.val)
	{
	case 0:	// 选择WiFi
		{
			pobj->devctx.wifi_index.val--;
			if (pobj->devctx.wifi_index.val < 0) {
				pobj->devctx.wifi_page_index.val--;
				if (pobj->devctx.wifi_page_index.val < 0) {
					pobj->devctx.wifi_page_index.val = pobj->devctx.wifi_page_index.max - 1;
					pobj->devctx.wifi_index.val = (pobj->devctx.wifi_index.max % 6) ? (pobj->devctx.wifi_index.max % 6 - 1) : 5;
				} else {
					pobj->devctx.wifi_index.val = 5;
				}
			}

			int pos = pobj->devctx.wifi_index.val + pobj->devctx.wifi_page_index.val * 6;
			struct sNode wifi_node;
			getElem(pobj->devctx.list_head, pos + 1, &wifi_node);
			pobj->devctx.wifi_signal_level.val = wifi_signal_level_switch(wifi_node.signal_level);
		}
		break;

	case 1:	// 选择连接或者忘记
		pobj->devctx.status_sel.val = 1 - pobj->devctx.status_sel.val;
		break;
	}

	return 0;
}

static int setup_search_wifi_switch_next(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	switch (pobj->devctx.wifi_connect_status.val)
	{
	case 0:	// 选择WiFi
		{
			pobj->devctx.wifi_index.val++;
			if (pobj->devctx.wifi_index.val > 5) {
				pobj->devctx.wifi_index.val = 0;
				pobj->devctx.wifi_page_index.val++;
				if (pobj->devctx.wifi_page_index.val > (pobj->devctx.wifi_page_index.max - 1)) {
					pobj->devctx.wifi_page_index.val = 0;
				}
			} else if ((pobj->devctx.wifi_index.val + pobj->devctx.wifi_page_index.val * 6) > pobj->devctx.wifi_index.max - 1) {
				pobj->devctx.wifi_index.val = 0;
				pobj->devctx.wifi_page_index.val = 0;
			}

			int pos = pobj->devctx.wifi_index.val + pobj->devctx.wifi_page_index.val * 6;
			struct sNode wifi_node;
			getElem(pobj->devctx.list_head, pos + 1, &wifi_node);
			pobj->devctx.wifi_signal_level.val = wifi_signal_level_switch(wifi_node.signal_level);
		}
		break;
	case 1:	// 选择连接或者忘记
		pobj->devctx.status_sel.val = 1 - pobj->devctx.status_sel.val;
		break;
	}

	return 0;
}

static int setup_password_choice(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;
	static char password[9] = {0};
	
	if (8 == pobj->devctx.password_enter_num.val && 10 == pobj->devctx.wifi_password_sel.val) {	// 已经输入8位密码
		int pos = pobj->devctx.wifi_index.val + pobj->devctx.wifi_page_index.val * 6;
		struct sNode wifi_node;
		getElem(pobj->devctx.list_head, pos + 1, &wifi_node);
		JN_Wifi_STA_Setup(wifi_node.essid, password);

		/* 获取状态判断连接是否成功 */
		JN_Wifi_STA_Getstatus(&pobj->devctx.wifi_status.val);

		/* 连接成功 */
		if (pobj->devctx.wifi_status.val) {
			pobj->curid = id_normal;

			char nvram_ssid[128] = {0}, nvram_password[128] = {0};
			nvram_load_param("STASSID", nvram_ssid);
			nvram_load_param("STAPasswd", nvram_password);
			if (strcmp(wifi_node.essid, nvram_ssid)) {	// 如果连接的WiFi和nvram中保存的WiFi1不一致
				nvram_save_param("STASSID", wifi_node.essid);
				nvram_save_param("STAPasswd", password);
				if (nvram_ssid[0] && nvram_password[0]) {
					nvram_save_param("STASSID2", nvram_ssid);
					nvram_save_param("STAPasswd2", nvram_password);
				}
				nvram_commit();
			}
		} else {	// 密码错误，重新输入
			pobj->devctx.wifi_password_sel.val = 0;
			pobj->devctx.wifi_password_sel.max = 9;
			pobj->devctx.password_enter_num.val = 0;
			memset(password, 0, 8);
		}
	} else if (pobj->devctx.password_enter_num.val < 8) {
		password[pobj->devctx.password_enter_num.val] = pobj->devctx.wifi_password_sel.val == 9 ? '0' : (pobj->devctx.wifi_password_sel.val + '1');
		if (++pobj->devctx.password_enter_num.val == 8) {
			pobj->devctx.wifi_password_sel.max = 10;
		}
	}

	return 0;
}

static int setup_password_switch_pre(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	pobj->devctx.wifi_password_sel.val--;
	if (pobj->devctx.wifi_password_sel.val < 0) {
		pobj->devctx.wifi_password_sel.val = pobj->devctx.wifi_password_sel.max;
	}

	return 0;
}

static int setup_password_switch_next(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	pobj->devctx.wifi_password_sel.val++;
	if (pobj->devctx.wifi_password_sel.val > pobj->devctx.wifi_password_sel.max) {
		pobj->devctx.wifi_password_sel.val = 0;
	}

	return 0;
}

/* 
 * 在normal界面短按5次上键进入信息界面
 * 选择升级，WiFi改为ap模式，ip地址为 192.168.11.123
 */
static int setup_normal_ver_info(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	
	if (0 == pobj->info.id[0]) {
		sprintf(pobj->info.id, "Linkcard");
		load_oeminfo_from_flash("OEM_SERIL_NUM", pobj->info.sn, 16);
		memcpy(pobj->info.gui_ver, GUI_VERSION, sizeof(GUI_VERSION));
		sprintf(pobj->info.hw_ver, "1.0");
		read_rootfs_version(pobj->info.sys_ver, 16);
	}
	
	pobj->curid = id_ver_info;
	pobj->devctx.enter_update.val = 0;
	pobj->devctx.status_sel.val = 0;

	return 0;
}

static int setup_ver_info_choice(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	if (0 == pobj->devctx.enter_update.val) {
		pobj->devctx.enter_update.val = 1;
	} else if (1 == pobj->devctx.enter_update.val) {
		if (pobj->devctx.status_sel.val) {
			pobj->curid = id_normal;
		} else {
			pobj->curid = id_update;
			system("/mnt/default/ap.sh on");
		}
	}
	return 0;
}

static int setup_ver_info_switch_pre(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	if (1 == pobj->devctx.enter_update.val) {
		pobj->devctx.status_sel.val = 1 - pobj->devctx.status_sel.val;
	}

	return 0;
}

static int setup_ver_info_switch_next(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	if (1 == pobj->devctx.enter_update.val) {
		pobj->devctx.status_sel.val = 1 - pobj->devctx.status_sel.val;
	}

	return 0;
}

static int setup_basedevs_handle_tick300ms(void *pso)
{
	UICtx_t *pobj = (UICtx_t*)pso;

	if (id_normal == pobj->curid && pobj->devctx.wifi.val) {
		JN_Wifi_STA_Getstatus(&pobj->devctx.wifi_status.val);
		// printf("wifi_status:%d\n", pobj->devctx.wifi_status.val);
		if (pobj->devctx.wifi_status.val) {
			pobj->devctx.wifi_signal_level.val = wifi_signal_level_switch(GetSignal());
		}
	}
	// if (tw9900_detect_video_input()) {
	// 	pobj->devctx.wifi.val = 0;
	// } else {
	// 	pobj->devctx.wifi.val = 1;
	// }

	return 0;
}

STATE_FUNC_ID setup_nomal = {{
	{SETUP_normal, 					KEY2_LONG, 					setup_normal_search_wifi},
	{SETUP_normal, 					KEY1_5TIMES, 				setup_normal_ver_info},
	{SETUP_normal, 					KEY3_SHORT, 				setup_normal_adjust_lcd_brightness},
	{SETUP_normal, 					KEY3_LONG, 					setup_normal_switch_wifi},
	},
};

STATE_FUNC_ID setup_search_wifi = {{
	{SETUP_search_wifi, 			KEY2_SHORT, 				setup_search_wifi_choice},
	{SETUP_search_wifi, 			KEY1_SHORT, 				setup_search_wifi_switch_pre},
	{SETUP_search_wifi, 			KEY3_SHORT, 				setup_search_wifi_switch_next},

	{SETUP_search_wifi, 			KEY2_LONG, 					setup_search_wifi_connect},
	},
};

STATE_FUNC_ID setup_password = {{
	{SETUP_password, 				KEY2_SHORT, 				setup_password_choice},
	{SETUP_password, 				KEY1_SHORT, 				setup_password_switch_pre},
	{SETUP_password, 				KEY3_SHORT, 				setup_password_switch_next},

	{SETUP_password, 				KEY2_LONG, 					setup_normal_search_wifi},
	},
};

STATE_FUNC_ID setup_ver_info = {{
	{SETUP_ver_info, 				KEY2_SHORT, 				setup_ver_info_choice},
	{SETUP_ver_info, 				KEY1_SHORT, 				setup_ver_info_switch_pre},
	{SETUP_ver_info, 				KEY3_SHORT, 				setup_ver_info_switch_next},
	},
};

STATE_FUNC_ID  setup_basedevs = {{
	{SETUP_basedevs,			KEY_TICK_300MS,				setup_basedevs_handle_tick300ms},
	},
};

static UICtx_t gUICtx = {0};
UICtx_t *getUICtx(void)
{
	return &gUICtx;
}

int Init_UICtx(UICtx_t *pobj, unsigned char mode)
{
	gpio_init();
	spi_gpio_init();
	SDL_zero(pobj->info);
	pobj->curid = id_normal;
	pobj->devctx.language.val = RUSSIAN;

	/* 获取WiFi的连接状态 */
	// JN_Wifi_STA_Getstatus(&pobj->devctx.wifi_status.val);
	// // printf("wifi_status:%d\n", pobj->devctx.wifi_status.val);
	// if (pobj->devctx.wifi_status.val) {
	// 	pobj->devctx.wifi_signal_level.val = wifi_signal_level_switch(GetSignal());
	// }
	
	int para_tmp;
    pobj->devctx.lcd_brightness.max = 9;
    pobj->devctx.lcd_brightness.min = 0;
	pobj->devctx.lcd_brightness.val = 5;
    if (0 == hal_get_para(PARA_BRIGHTNESS, &para_tmp)) {
        pobj->devctx.lcd_brightness.val = para_tmp;
    }
	sony_driver_brightness_level(pobj->devctx.lcd_brightness.val);

	return 0;
}


/*******************************************************	
	handle_event
	事件处理中心, 程序运行的核心函数，输入事件，跟新状态
	
	input:   		pobj   设备句柄
					keyval 按键驱动
	output  :       1: 需要跟新UI显示
					0: 无需跟新UI显示
	输出给GUI,  决策GUI是否需要跟新handle_gui();
********************************************************/
int  handle_event(UICtx_t * pobj, eKeyVal keyval)
{
	int i;
	int ret =0;

	/*****************************************************
	* 1. 任何状态下都需要执行的事件，主要是电源和LED灯
	*/	
	for(i = 0; i < KEY_NULL; i++)
	{
		if (setup_basedevs.func_id[i].keyval == keyval) {
			if (setup_basedevs.func_id[i].func_ptr) {
				setup_basedevs.func_id[i].func_ptr(pobj);
				ret = 1; //不需要跟新UI，都留给下面具体界面处理
			}
		}
	}

	switch(pobj->curid)
	{
	case id_normal:
		for (i = 0; i < KEY_NULL; i++) {
			if (setup_nomal.func_id[i].keyval == keyval) {
				if (setup_nomal.func_id[i].func_ptr) {
					setup_nomal.func_id[i].func_ptr(pobj);
					ret = 1;
				}
			}
		}
		break;
	case id_search_wifi:
		for (i = 0; i < KEY_NULL; i++) {
			if (setup_search_wifi.func_id[i].keyval == keyval) {
				if (setup_search_wifi.func_id[i].func_ptr) {
					setup_search_wifi.func_id[i].func_ptr(pobj);
					ret = 1;
				}
			}
		}
		break;
	case id_password:
		for (i = 0; i < KEY_NULL; i++) {
			if (setup_password.func_id[i].keyval == keyval) {
				if (setup_password.func_id[i].func_ptr) {
					setup_password.func_id[i].func_ptr(pobj);
					ret = 1;
				}
			}
		}
		break;
	case id_ver_info:
		for (i = 0; i < KEY_NULL; i++) {
			if (setup_ver_info.func_id[i].keyval == keyval) {
				if (setup_ver_info.func_id[i].func_ptr) {
					setup_ver_info.func_id[i].func_ptr(pobj);
					ret = 1;
				}
			}
		}
		break;
	}

	return ret;
}